package com.syni.mdd.yhd.common.all.utils.auth;

import com.alibaba.fastjson.JSON;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.syni.mdd.sjb.common.component.utils.common.utils.DateTimeUtils;
import com.syni.mdd.sjb.common.component.utils.common.utils.RequestHeaderData;
import com.syni.mdd.sjb.common.component.utils.common.utils.WebUtils;
import com.syni.mdd.yhd.common.all.constants.Constants;
import com.syni.mdd.yhd.common.all.entity.user.BmsUser;
import com.syni.mdd.yhd.common.all.utils.TokenUtils;
import com.syni.mdd.sjb.common.component.utils.redis.utils.RedisTemplateUtils;;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @className JwtTokenUtil
 * @description TOO
 * @Author cfx
 * @DATE 2020/4/10 9:39
 * @VERSION 1.0
 **/
@Component
public class JwtTokenAuth implements TokenAuth {
    private static Logger logger = LoggerFactory.getLogger(JwtTokenAuth.class);
    @Value("${app.token.expire}")
    private int VALID_TIME; // token有效期(秒)
    public static final int TOKEN_ERROR = -1; // 非法
    public static final int TOKEN_OVERDUE = 0; // 无效
    public static final int TOKEN_SUCCESS = 1; // 验证成功

    @Override
    public String getToken(String userId, String roleId) {
        int client = RequestHeaderData.getRequestHeaderData().getClient();
        if(client == Constants.ANDROID_CLIENT || client == Constants.IOS_CLIENT){
            client = Constants.APP_CLIENT;
        }
        String userTokenKey = Constants.REDIS_KEY_TOKEN + String.format("%s:%s:%s",userId,roleId,client);
        Date expireTime = DateTimeUtils.addDay(new Date(),VALID_TIME);
        AuthUserBo authUserBo = new AuthUserBo(userId,roleId,client);
        String token = JWT.create().withAudience(authUserBo.toString()).withExpiresAt(expireTime)
                .sign(Algorithm.HMAC256(WebUtils.MD5(userId + roleId)));
        //维护token，实现token失效功能
        RedisTemplateUtils.getRedisTemplate().opsForValue().set(userTokenKey,token,VALID_TIME, TimeUnit.DAYS);
        return token;
    }

    public String getToken(BmsUser bmsUser, String roleId) {
        int client = RequestHeaderData.getRequestHeaderData().getClient();
        if(client == Constants.ANDROID_CLIENT || client == Constants.IOS_CLIENT){
            client = Constants.APP_CLIENT;
        }
        String userId = bmsUser.getId().toString();
        String userTokenKey = Constants.REDIS_KEY_TOKEN + String.format("%s:%s:%s",userId,roleId,client);
        Date expireTime = DateTimeUtils.addDay(new Date(),VALID_TIME);
        AuthUserBo authUserBo = new AuthUserBo(bmsUser,roleId,client);
        String token = JWT.create().withAudience(authUserBo.toString()).withExpiresAt(expireTime)
                .sign(Algorithm.HMAC256(WebUtils.MD5(userId + roleId)));
        //维护token，实现token失效功能
        RedisTemplateUtils.getRedisTemplate().opsForValue().set(userTokenKey,token,VALID_TIME, TimeUnit.DAYS);
        return token;
    }

    public String getToken(String userId, String roleId, Integer client){
        if(client == Constants.ANDROID_CLIENT || client == Constants.IOS_CLIENT){
            client = Constants.APP_CLIENT;
        }
        String userTokenKey = Constants.REDIS_KEY_TOKEN + String.format("%s:%s:%s",userId,roleId,client);
        Date expireTime = DateTimeUtils.addDay(new Date(),VALID_TIME);
        AuthUserBo authUserBo = new AuthUserBo(userId,roleId,client);
        String token = JWT.create().withAudience(authUserBo.toString()).withExpiresAt(expireTime)
                .sign(Algorithm.HMAC256(WebUtils.MD5(userId + roleId)));
        //维护token，实现token失效功能
        RedisTemplateUtils.getRedisTemplate().opsForValue().set(userTokenKey,token,VALID_TIME, TimeUnit.DAYS);
        return token;
    }

    @Override
    public String getToken(String userId, String roleId, boolean isRefresh) {
        int client = RequestHeaderData.getRequestHeaderData().getClient();
        if(client == Constants.ANDROID_CLIENT || client == Constants.IOS_CLIENT){
            client = Constants.APP_CLIENT;
        }
        String userTokenKey = Constants.REDIS_KEY_TOKEN + String.format("%s:%s:%s",userId,roleId,client);
        if(!isRefresh){
            if(RedisTemplateUtils.getRedisTemplate().hasKey(userTokenKey)){
                return RedisTemplateUtils.getRedisTemplate().opsForValue().get(userTokenKey).toString();
            }
        }
        return getToken(userId,roleId,client);
    }


    public String getToken(String userId,String roleId,Integer client,boolean isNotRefresh){
        String userTokenKey = Constants.REDIS_KEY_TOKEN + String.format("%s:%s:%s",userId,roleId,client);
        if(!isNotRefresh){
            if(RedisTemplateUtils.getRedisTemplate().hasKey(userTokenKey)){
                return RedisTemplateUtils.getRedisTemplate().opsForValue().get(userTokenKey).toString();
            }
        }
        return getToken(userId,roleId,client);
    }

    /**
     * 校验token的有效性
     * @param token
     * @return
     */
    public int checkToken(String token,String userId) {
        if (token == null) {
            return TOKEN_ERROR;
        }
        try{
            List<String> tokenData = JWT.decode(token).getAudience();
            if(!(tokenData.size() > 0)) {
                return TOKEN_ERROR;
            }
            //检查token是否无效
            String userData = tokenData.get(0);
            AuthUserBo authUserBo = JSON.parseObject(userData, AuthUserBo.class);
            String deUserId = authUserBo.getUserId();
            String roleId = authUserBo.getRoleId();
            Integer client = authUserBo.getClient();
            String userTokenKey = Constants.REDIS_KEY_TOKEN + String.format("%s:%s:%s",deUserId,roleId,client);
            if(!RedisTemplateUtils.getRedisTemplate().hasKey(userTokenKey)){
                return TOKEN_OVERDUE;
            }
            String checkToken = RedisTemplateUtils.getRedisTemplate().opsForValue().get(userTokenKey).toString();
            if(!checkToken.equals(token)){
                return TOKEN_OVERDUE;
            }
            JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(WebUtils.MD5(deUserId + roleId))).build();
            jwtVerifier.verify(token);
            //设置为全局
            TokenUtils.getUserThreadLocal().set(deUserId);
            return TOKEN_SUCCESS;
        }catch (Exception e) {
            logger.info(e.toString());
        }
        return TOKEN_ERROR;
    }

    @Override
    public int checkToken(String token) {
        if (token == null) {
            return TOKEN_ERROR;
        }
        try{
            List<String> tokenData = JWT.decode(token).getAudience();
            if(!(tokenData.size() > 0)) {
                return TOKEN_ERROR;
            }
            //检查token是否无效
            String userData = tokenData.get(0);
            AuthUserBo authUserBo = JSON.parseObject(userData, AuthUserBo.class);
            String deUserId = authUserBo.getUserId();
            String roleId = authUserBo.getRoleId();
            Integer client = authUserBo.getClient();
            String userTokenKey = Constants.REDIS_KEY_TOKEN + String.format("%s:%s:%s",deUserId,roleId,client);
            if(!RedisTemplateUtils.getRedisTemplate().hasKey(userTokenKey)){
                return TOKEN_OVERDUE;
            }
            String checkToken = RedisTemplateUtils.getRedisTemplate().opsForValue().get(userTokenKey).toString();
            if(!checkToken.equals(token)){
                return TOKEN_OVERDUE;
            }
            JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(WebUtils.MD5(deUserId + roleId))).build();
            jwtVerifier.verify(token);
            //设置为全局
            TokenUtils.getUserThreadLocal().set(deUserId);
            return TOKEN_SUCCESS;
        }catch (Exception e) {
            logger.info(e.toString());
        }
        return TOKEN_ERROR;
    }

    @Override
    public boolean cancellation(String userTokenKey) {
        if(RedisTemplateUtils.getRedisTemplate().hasKey(userTokenKey)){
            RedisTemplateUtils.getRedisTemplate().delete(userTokenKey);
        }
        return true;
    }

    @Override
    public int checkTokenExist(AuthUserBo authUserBo) {
        String deUserId = authUserBo.getUserId();
        String roleId = authUserBo.getRoleId();
        Integer client = authUserBo.getClient();
        String userTokenKey = Constants.REDIS_KEY_TOKEN + String.format("%s:%s:%s",deUserId,roleId,client);
        if(!RedisTemplateUtils.getRedisTemplate().hasKey(userTokenKey)){
            return 0;
        }
        return 1;
    }
}
